#pragma once
#include <Common/headers.h>

namespace occ {
	class Plane {
	public:
		union {
			struct {
				vec3f normal;
				occFloat d;
			};
			struct {
				occFloat a, b, c, d;
			};
		};


		Plane(occFloat a = 0, occFloat b = 0, occFloat c = 0, occFloat d = 0) :
			d(d), normal(a, b, c) {}

		Plane(occFloat d, const vec3f& n) :d(d), normal(n) {}

		Plane(const vec3f& v1, const vec3f& v2, const vec3f& v3) {
			normal = normalize(cross(v2 - v1, v3 - v1));
			d = -dot(normal, v1);
		}
	};

	struct Triangle {
		union {
			struct {
				vec3f v1, v2, v3;
			};
			vec3f _v[3];
		};

		Triangle() {}

		Triangle(const vec3f& v1, const vec3f& v2, const vec3f& v3) :
			v1(v1), v2(v2), v3(v3) {}

		Triangle(const vec4f& v1, const vec4f& v2, const vec4f& v3) :
			v1(v1.x, v1.y, v1.z), v2(v2.x, v2.y, v2.z), v3(v3.x, v3.y, v3.z) {}

		vec3f center() const {
			return (v1 / (occFloat)3.0 + v2 / (occFloat)3.0 + v3 / (occFloat)3.0);
		}

		occFloat centerZ() const {
			return v1.z / (occFloat)3.0 + v2.z / (occFloat)3.0 + v3.z / (occFloat)3.0;
		}
	};

	bool inverseZCompare(const Triangle& a, const Triangle& b) {
		return a.centerZ() > b.centerZ();  // larger z <=> nearer to the observer
	}

	class InverseZCompareIdx {
	private:
		Triangle* tri;
	public:
		InverseZCompareIdx(Triangle* tri) :tri(tri) {}
		// a larger z means closer to the observer
		bool operator()(int i, int j) const { return tri[i].centerZ() > tri[j].centerZ(); }
	};

	class ZCompareIdx {
	private:
		Triangle* tri;
	public:
		ZCompareIdx(Triangle* tri) :tri(tri) {}
		// a larger z means closer to the observer
		bool operator()(int i, int j) const { return tri[i].centerZ() < tri[j].centerZ(); }
	};
}